package com.dynomedia.esearch.util.groupkeycache;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dynomedia.esearch.util.groupkeycache.util.ConsumerThreadPool;
import com.dynomedia.esearch.util.groupkeycache.util.GkcConfig;

/**
 * @author Administrator
 * @version 1.0
 * @created 19-十月-2009 16:50:13
 */
public class GroupkeyCache {
	
	private static final Log logger = LogFactory.getLog(GroupkeyCache.class);

	private static Map<Long,Groupkey> groupkeys = new HashMap<Long,Groupkey>();	
	
	private static LinkedBlockingQueue<Groupkey> groupkeysQueue = new LinkedBlockingQueue<Groupkey>();
	
	/** 默认组ID*/
	protected static final Long defaultGroupId = Long.MAX_VALUE;
	/** 默认组名*/
	protected static final String defaultGroupname = "";
	
	/** groupkey 默认的排序时间*/
	private static Integer sortInterval = GkcConfig.getInstance().getGroupkeySortInterval();

	static{
		GroupkeyConsumer.start();init();
	}

	/**
	 * 私有构造方法
	 */
	private GroupkeyCache(){}
	
	public static void start(){}
	
	private static void init(){
		long startime = System.currentTimeMillis();
		File[] gkDirs = GkcConfig.getInstance().getDataDir().listFiles();
		if(gkDirs!=null)
			for(File dir:gkDirs){
				try{
					newGroupkey(Long.parseLong(dir.getName()),defaultGroupname,GkcConfig.getInstance().getGroupkeySize());
				}catch(Exception e){
					logger.error("GroupkeyCache init error!can't load cachefile from "+dir.getAbsolutePath(),e);
					continue;
				}
			}
		if(logger.isInfoEnabled()) logger.info("GroupkeyCache init complete,gkDirs.size:"+(gkDirs==null?0:gkDirs.length)+" init time:"+(System.currentTimeMillis() - startime)+" ms");		
	}
	
	/**
	 * 向默认组添加采样数据
	 * baipeng wrote at 上午10:28:56 2009-11-4
	 * @param key
	 * @return
	 */
	public static boolean add(String key){return add(defaultGroupId,defaultGroupname,key);}
	
	/**
	 * 向指定组添加采样数据
	 * baipeng wrote at 上午10:29:14 2009-11-4
	 * @param id
	 * @param key
	 * @return
	 */
	public static boolean add(Long id,String key){return add(id,defaultGroupname,key);}

	/**
	 * 外部写入线程调用
	 * 
	 * @param id
	 * @param title
	 * @param searchkey
	 */
	public static boolean add(Long id, String group, String key){
		Groupkey groupkey = get(id);
		if(groupkey!=null){
			return groupkey.add(key);
		}else{
			Groupkey newgroupkey = newGroupkey(id,group,GkcConfig.getInstance().getGroupkeySize());
			return newgroupkey.add(key);
		}
	}
	
	/**
	 * 获得默认的分组对象
	 * baipeng wrote at 上午10:31:58 2009-11-4
	 * @return
	 */
	public static Groupkey get(){return get(defaultGroupId);}

	/**
	 * add方法内部调用
	 * 
	 * @param id
	 */
	public static Groupkey get(Long id){
		return groupkeys.get(id);
	}
	
	/**
	 * 获得默认分组中的排序数组
	 * baipeng wrote at 上午10:38:13 2009-11-4
	 * @return
	 */
	public static List<Topkey> getTopkey(){
		return getTopkey(defaultGroupId);
	}
			
	/**
	 * 获得指定分组中的排序数组
	 * baipeng wrote at 上午10:36:39 2009-11-4
	 * @param id
	 * @return
	 */
	public static List<Topkey> getTopkey(Long id){
		if(groupkeys.get(id)!=null) return groupkeys.get(id).getSortedTopkeys();
		return new ArrayList<Topkey>(0);
	}
	
	/**
	 * 获得默认分组，指定采样值（Key）的Topkey对象
	 * baipeng wrote at 上午10:43:35 2009-11-4
	 * @param key
	 * @return
	 */
	public static Topkey getTopkey(String key){
		return getTopkey(defaultGroupId,key);
	}
	
	/**
	 * 获得指定分组，指定采样值（Key）的Topkey对象
	 * baipeng wrote at 上午10:40:58 2009-11-4
	 * @param id
	 * @param key
	 * @return
	 */
	public static Topkey getTopkey(Long id,String key){
		if(groupkeys.get(id)!=null) return groupkeys.get(id).get(key);
		return new Topkey(key,0);
	}

	/**
	 * 根据id创建新的Groupkey对象，方法需要同步。方法体内部需要调用get方法二次验证其他线程是否已经创建该id的Groupkey对象。
	 * 
	 * @param id
	 * @param name
	 * @param size
	 */
	private synchronized static Groupkey newGroupkey(Long id, String groupname, Integer size){
		if(get(id)!=null) return get(id);
		Groupkey gkey = new Groupkey(id,groupname,size,sortInterval);
		groupkeys.put(id,gkey);
		groupkeysQueue.add(gkey);
		if(logger.isInfoEnabled()) logger.info("GroupkeyCache create new groupkey for id:"+id+" group:"+groupname);
		return get(id);
	}

	public static LinkedBlockingQueue<Groupkey> getGroupkeysQueue() {
		return groupkeysQueue;
	}

	/**
	 * Monitor线程调用
	 * baipeng wrote at 上午10:40:37 2009-11-3
	 * @param transferMapContainer
	 * @return
	 */
	public synchronized static Map<Long, Groupkey> getGroupkeys(Map<Long, Groupkey> transferMapContainer) {
		transferMapContainer.putAll(groupkeys);
		return transferMapContainer;
	}
	
	/**
	 * 强制释放GroupkeyCache所占用的缓存空间
	 * baipeng wrote at 上午10:33:33 2009-11-4
	 */
	public static void clear(){
		groupkeys.clear();
		groupkeysQueue.clear();
	}
	
	/**
	 * 关闭和GroupkeyCache相关的所有维护线程
	 * baipeng wrote at 下午02:00:04 2009-11-6
	 */
	public static void shutdown(){
		clear();
		ConsumerThreadPool.shutdown();
	}

}